from PySide6.QtCore import Property, Qt, QObject, Slot, Signal
from PySide6.QtQml import QmlElement, QQmlComponent
from PySide6.QtCore import QTimer, QUrl
from PySide6 import QtCore
from time import strftime, localtime
# import myglobal
import logging
import pandas

QML_IMPORT_NAME = "iproapps.besttodolist"
QML_IMPORT_MAJOR_VERSION = 1


class PandasModel(QtCore.QAbstractTableModel):
    def __init__(self):
        super().__init__()
        self._data = pandas.DataFrame()
        self.properties = []

    def gen_choise(self):
        i = 0
        r = []
        # logging.info(self.properties)
        for p in self.properties:
            # logging.info(p)
            # logging.info(p["delegate"])            
            if p["delegate"] is None:
                r.append("""DelegateChoice {
                    column: %d
                    delegate: TextField  {
                        text: model.display
                        implicitWidth: %d
                        readOnly:true
                    }
                }""" % (i, p["width"]))
            elif "edit" == p["delegate"]:
                r.append("""DelegateChoice {
                    column: %d
                    delegate: TextField  {
                        text: model.display
                        implicitWidth: %d
                    }
                }""" % (i, p["width"]))
            elif "check" == p["delegate"]:
                r.append("""DelegateChoice {
                    column: %d
                    delegate: CheckBox {
                        checked: model.display
                        onToggled: model.display = checked
                    }
                }""" % i)
            elif "double" == p["delegate"]:
                r.append("""DelegateChoice {
                    column: %d
                    delegate: TextField {
                        property var value: model.display
                        implicitWidth: %d
                        onValueChanged: ()=>{
                            //console.log(value)
                            let r=parseFloat(value)
                            text=r.toFixed(%d)
                        }
                        readOnly:true
                    }
                }""" % (i, p["width"], p["point_num"]))
            elif "floatEdit" == p["delegate"]:
                r.append("""DelegateChoice {
                    column: %d
                    delegate: TextField  {
                        text: model.display
                        implicitWidth: %d
                    }
                }""" % (i, p["width"]))
            i += 1
        return "".join(r)

    @Slot(result=QObject)
    def createChooser(self):
        choies = self.gen_choise()
        qml = """import QtQuick
            import QtQuick.Controls
            import Qt.labs.qmlmodels
            DelegateChooser {
                        %s
        }""" % choies
        component = QQmlComponent(myglobal.engine)
        component.setData(qml.encode("utf-8"), QUrl())
        chooser = component.create()
        return chooser

    def setDataFrame(self, data, properties=[]):
        self.beginResetModel()
        self._data = data
        self.properties = properties
        self.endResetModel()

    def setObjects(self, data, properties=[]):
        self.beginResetModel()
        self._data = data
        self.properties = properties
        self.endResetModel()

    def setObjectsOnly(self, data):
        self.beginResetModel()
        self._data = data
        self.endResetModel()

    def getObject(self, index):
        if not index.isValid():
            return None
        object_index = index.row()
        try:
            return self._data.iloc[object_index]
        except IndexError:
            return None

    def getObjectRow(self, row):
        try:
            return self._data.iloc[row]
        except IndexError:
            return None

    def getProperty(self, index):
        if not index.isValid():
            return None
        property_index = index.column()
        try:
            return self.properties[property_index]
        except IndexError:
            return None

    def data(self, index, role):
        if role in [Qt.DisplayRole, Qt.EditRole]:
            value = self._data.iloc[index.row(), index.column()]
            return value
            # if role==Qt.DisplayRole:
            #     column=index.column()
            #     if myglobal.bridge.db.properties[column]["delegate"]=="double":
            #         return myglobal.bridge.db.doublefmt % value
            #     else:
            #         return value
            # return value

    def setData(self, index, value, role=Qt.EditRole):
        # logging.info(index)
        # logging.info(index.row())
        # logging.info(index.column())
        # if not index.isValid():
        #     logging.info("index invalid")
        #     return False
        # logging.info("index valid")
        obj = self.getObject(index)
        prop = self.getProperty(index)
        # logging.info(obj)
        # logging.info(prop)
        if (obj is None) or (prop is None):
            logging.info("obj is None or prop is None")
            return None
        logging.info(type(value))
        obj.iloc[index.column()] = value
        return True

    def flags(self, index):
        flags = QtCore.QAbstractTableModel.flags(self, index)
        if not index.isValid():
            return flags
        prop = self.getProperty(index)
        if prop is None:
            return flags
        flags |= Qt.ItemIsEnabled
        flags |= Qt.ItemIsSelectable
        mode = prop.get('mode', "Read/Write")
        if "Write" in mode:
            flags |= Qt.ItemIsEditable
        return flags

    def rowCount(self, *args, **kwargs):
        return self._data.shape[0]

    def columnCount(self, *args, **kwargs):
        return self._data.shape[1]

    def headerData(self, col, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            if col < len(self.properties):
                p = self.properties[col]
                if p is not None:
                    return p["header"]
                else:
                    return str(self._data.columns[col])
            # return QtCore.QVariant(self.properties[col]['header'])
        return None

    def sort(self, Ncol, order):
        """Sort table by given column number.
        """
        self.layoutAboutToBeChanged.emit()  # SIGNAL("layoutAboutToBeChanged()"))
        print(Ncol)
        # self.objects =sorted(self.objects, key=operator.itemgetter(Ncol))        
        try:
            # self._data =sorted(self.objects,key=lambda x: getattr(x,self.properties[Ncol]["attr"]))
            colname = self._data.columns[Ncol]
            if order == Qt.DescendingOrder:
                self._data = self._data.sort_values(colname, ascending=False)
            else:
                self._data = self._data.sort_values(colname, ascending=True)
        except TypeError:
            pass
        self.layoutChanged.emit()  # SIGNAL("layoutChanged()"))


@QmlElement
class Bridge(QObject):
    updated = Signal(str, arguments=['time'])

    def __init__(self):
        super().__init__()
        self.db = None
        myglobal.bridge = self
        self.timer = QTimer()
        self.timer.setInterval(1000)  # msecs 100 = 1/10th sec
        self.timer.timeout.connect(self.update_time)
        self.timer.start()
        self._model = PandasModel()
        self.set_database()
        self.df = self.db.getDataDays(200)
        self._model.setObjects(self.df, self.db.properties)
        self._model2 = PandasModel()

    outputChanged = Signal()

    @Property(str, notify=outputChanged)
    def output(self):
        # logging.info(config_json.setting)
        return config_json.setting["output_folder"]

    @output.setter
    def output(self, shoeSize):
        logging.info("set")
        config_json.setting["output_folder"] = shoeSize

    inputChanged = Signal()

    @Property(str, notify=inputChanged)
    def input(self):
        # logging.info(config_json.setting)
        return config_json.setting["database"]

    @input.setter
    def input(self, shoeSize):
        config_json.setting["database"] = shoeSize

    def set_database(self):
        # self.ui.groupBox_images.setVisible(False)
        if config_json.setting["sblx"] in ["ajl_pdf", "6300", "icap"]:  # icp
            from icp import MyDb
            append = config_json.setting["append"].get("icp", {})
            self.db = MyDb(self)
        elif config_json.setting["sblx"] in ["spec", "4460"]:  # spec
            append = config_json.setting["append"].get("spec", {})
            self.db = spectro.MyDb(self)
        elif config_json.setting["sblx"] == "weight":
            append = config_json.setting["append"].get("weight", {})
            self.db = weight.MyDb(self)
        elif config_json.setting["sblx"] == "diding":
            append = config_json.setting["append"].get("diding", {})
            self.db = diding.MyDb(self)
        elif config_json.setting["sblx"] == "guangdu":
            append = config_json.setting["append"].get("guangdu", {})
            self.db = guangdu.MyDb(self)
        elif config_json.setting["sblx"] == "zwk":
            append = config_json.setting["append"].get("zwk", {})
            self.db = zwk.MyDb(self)
        elif config_json.setting["sblx"] in ["ajl8900", "icap_q", "ncs300"]:  # icpms
            from icpms import MyDb
            append = config_json.setting["append"].get("icpms", {})
            self.db = MyDb(self)
        else:  # csonh
            append = config_json.setting["append"].get("csonh", {})
            self.db = csonh.MyDb(self)
        logging.info(append)

    modelChanged = Signal()

    @Property(QObject, notify=modelChanged)
    def model(self):
        return self._model

    model2Changed = Signal()

    @Property(QObject, notify=model2Changed)
    def model2(self):
        return self._model2

    @Slot()
    def up(self):
        pass

    @Slot()
    def down(self):
        pass

    @Slot()
    def down_all(self):
        pass

    @Slot()
    def import_last(self):
        self.df = self.db.getDataDays(200)
        self._model.setObjects(self.df, self.db.properties)
        self.modelChanged.emit()

    @Slot(str)
    def import_file(self, url):
        logging.info(url)
        path = QtCore.QUrl(url).toLocalFile()
        config_json.setting["database"] = path
        self.df = self.db.getDataDays(200)
        self._model.setObjects(self.df, self.db.properties)
        self.modelChanged.emit()

    def update_time(self):
        curr_time = strftime("%H:%M:%S", localtime())
        self.updated.emit(curr_time)


if __name__ == '__main__':
    b = Bridge()
    b.getPacks("{}")
